/*
 * Sync class  
 * in this class we calculate time air and transfer data on user to other device 
 *  data include two parameters 
 *  1. Who the data belongs
 *  2. data
 *  data we send 
 *  1. time system for calculate time air for calculate time air we send 50 message 
 *  2. user name of user in facebook
 *  3. user id of user in facebook profile picture 
 *  4. device name 
 */
package com.warrior.bluetooth;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.util.Log;

import com.warrior.main.MyApp;
import com.warrior.main.MyApp.IDataReceiveSync;
import com.warrior.main.MyFacebook;
import com.warrior.main.MyLog;

public class Sync implements IDataReceiveSync {
	
	private final static int MAX_PACKEAGES = 49;
	private final static long DATA_TIME_SYSTEM = 1000,DATA_TIME_AIR = 1001,DATA_FACEBOOK_USER_NAME = 1002;
	private final static long DATA_FACEBOOK_USER_ID = 1003,DATA_DEVICE_NAME = 1004,DATA_FINISH = 1005;
	private final static String DATA_FACEBOOK_NO_NAME = "no name",DATA_FACEBOOK_NO_ID = "no id";
	private static final String DATA_SEPARATION = "!";
	
	private String[] arrAirTime = new String[MAX_PACKEAGES + 1];
	private String[] arrTotalTime = new String[MAX_PACKEAGES + 1];
	private long avgAirTime = 0,avgTotalRoundTrip = 0;
	private long timeAir = 0;
	private ServerSync server;
	private ClientSync client;
	private CommHandler commHandler;
	private ISyncStateChanged iSyncStateChanged;
	private MyApp app;
	
	public Sync(MyApp app){
		this.app = app;
		this.commHandler = app.getCommHandler();
		server = new ServerSync();
		client = new ClientSync();
		app.setDataRecevieSyncListener(this);
	}
	
	public void startSync(){
		server.serverStartSync();
	}
	public void setSyncStateChangedListener(ISyncStateChanged iSyncStateChanged){
		this.iSyncStateChanged = iSyncStateChanged;
	}
	public static long getSystemTime(){
		return System.currentTimeMillis();
	}
	public static String getDateTime(){
		return " date: " + Calendar.getInstance().getTime().toString();
	}
	public static void waitTime(long time){
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			Log.d(MyLog.SYNC_EXEPTION,"InterruptedException when thread go to sleep message: " + e.getMessage());
		}
	}
	public long getTimeAir(){
		return timeAir; 
	}
	public void dataRecevieSync(MyMessage myMessage) {
		if(app.isServer()){
			server.syncRunning(myMessage);
		}
		else{
			client.syncRunning(myMessage);
		}
		
	}
	private String buildData(Object dataToWhere,Object data){
		StringBuilder strB = new StringBuilder();
		strB.append(dataToWhere);
		strB.append(DATA_SEPARATION);
		strB.append(data);
		return strB.toString();
	}
	private class ServerSync
	{
		private int counterReceiveData = 0;
		private final static int MAX_RECEIVE_DATA = MAX_PACKEAGES;
		private long sendTime = 0;
		String sendData;
		
		public void serverStartSync()
		{
			Log.d(MyLog.SYNC,"before startSync");
			// send the first message to client
			sendTime = getSystemTime();
			sendData = DATA_TIME_SYSTEM + DATA_SEPARATION + String.valueOf(sendTime);
			commHandler.writeToRmoteDevice(sendData);
			iSyncStateChanged.startedSync();
		}
		public void syncRunning(MyMessage myMessage)
		{
			Log.d(MyLog.SYNC,"data:" + myMessage.getSData());
			// create separation of data
			String[] strReceivesData = myMessage.getSData().split(DATA_SEPARATION);
			long typeDataReceived = Long.parseLong(strReceivesData[0]);
			
			if(typeDataReceived == DATA_TIME_SYSTEM){
				// receive data
				long deltaInClientSide = Long.parseLong(strReceivesData[1]);
				long deltaNsRoundTrip = (myMessage.getReceiveTime()-sendTime);
				long airTimeTotal = deltaNsRoundTrip - deltaInClientSide;
				arrAirTime[counterReceiveData] = "air time is:" + airTimeTotal;
				arrTotalTime[counterReceiveData] = "round trip is:" + deltaNsRoundTrip;
				avgAirTime += airTimeTotal;
				avgTotalRoundTrip += deltaNsRoundTrip;
				if(counterReceiveData >= MAX_RECEIVE_DATA){
					writeResultSync();
					timeAir = (avgAirTime/(MAX_RECEIVE_DATA*2));
					sendData = buildData(DATA_TIME_AIR,timeAir);
					commHandler.writeToRmoteDevice(sendData);
					return;
				}
				counterReceiveData++;
				// send data
				sendTime = getSystemTime();
				sendData = buildData(DATA_TIME_SYSTEM,sendTime);
				commHandler.writeToRmoteDevice(sendData);
			}
			else if(typeDataReceived == DATA_TIME_AIR){
				// receive data
				int clientTimeAir = Integer.parseInt(strReceivesData[1]);
				// send data
				sendData = buildData(DATA_FACEBOOK_USER_NAME,DATA_FACEBOOK_NO_NAME);
				
				if(timeAir == clientTimeAir){
					MyFacebook fb = app.getFacebook();
					if(fb.isOpenedConnection()){
						sendData = buildData(DATA_FACEBOOK_USER_NAME,fb.getUser().getName());
					}
					commHandler.writeToRmoteDevice(sendData);
				}
			}
			else if(typeDataReceived == DATA_FACEBOOK_USER_NAME){
				MyFacebook fb = app.getFacebook();
				// receive data
				// if data received not equals to DATA_FACEBOOK_NO_NAME so other device connected with facebook
				// if not other device not connected with facebook
				if(!strReceivesData[1].equals(DATA_FACEBOOK_NO_NAME)){
					fb.setCompetitorUserName(strReceivesData[1]);
				}
				// send data
				sendData = buildData(DATA_FACEBOOK_USER_ID,DATA_FACEBOOK_NO_ID);
				if(fb.isOpenedConnection()){
					sendData = buildData(DATA_FACEBOOK_USER_ID,fb.getUser().getId());
				}
				commHandler.writeToRmoteDevice(sendData);
			}
			else if(typeDataReceived == DATA_FACEBOOK_USER_ID){
				// receive data
				// if data received not equals to DATA_FACEBOOK_NO_ID so other device connected with facebook
				// if not other device not connected with facebook
				if(!strReceivesData[1].equals(DATA_FACEBOOK_NO_ID)){
					app.getFacebook().setCompetitorUserID(strReceivesData[1]);
				}
				// send data
				sendData = buildData(DATA_DEVICE_NAME,app.getMyDeviceName());
				commHandler.writeToRmoteDevice(sendData);
			}
			else if(typeDataReceived == DATA_DEVICE_NAME){
				// receive data
				app.setCompetitorDeviceName(strReceivesData[1]);
				// send data
				sendData = buildData(DATA_FINISH,DATA_FINISH);
				commHandler.writeToRmoteDevice(sendData);
			}
			else if(typeDataReceived == DATA_FINISH){
				iSyncStateChanged.finishedSync();
			}
		}
	}
	private class ClientSync{
		
		private String sendData;
		private boolean isStarted = false;
		
		public void syncRunning(MyMessage myMessage)
		{
			long receiveTime = myMessage.getReceiveTime();
			Log.d(MyLog.SYNC,"data:" + myMessage.getSData());
			String[] strReceivesData = myMessage.getSData().split(DATA_SEPARATION);
			long recevieToWhere = Long.parseLong(strReceivesData[0]);
			
			if(recevieToWhere == DATA_TIME_SYSTEM){
				long sendTime=getSystemTime();
				long deltaInsideClient = sendTime - receiveTime;
				
				sendData = buildData(DATA_TIME_SYSTEM,deltaInsideClient);
				commHandler.writeToRmoteDevice(sendData);
				
				if(!isStarted){
					isStarted = true;
					iSyncStateChanged.startedSync();
				}
			}
			else if(recevieToWhere == DATA_TIME_AIR){
				// receive data
				timeAir = Long.parseLong(strReceivesData[1]);
				// send data
				sendData = buildData(DATA_TIME_AIR,timeAir);
				commHandler.writeToRmoteDevice(sendData);
			}
			else if(recevieToWhere == DATA_FACEBOOK_USER_NAME){
				MyFacebook fb = app.getFacebook();
				// receive data
				// if data received not equals to DATA_FACEBOOK_NO_NAME so other device connected with facebook
				// if not other device not connected with facebook
				if(!strReceivesData[1].equals(DATA_FACEBOOK_NO_NAME)){
					fb.setCompetitorUserName(strReceivesData[1]);
				}
				// send data
				sendData = buildData(DATA_FACEBOOK_USER_NAME,DATA_FACEBOOK_NO_NAME);
				if(fb.isOpenedConnection()){
					sendData = buildData(DATA_FACEBOOK_USER_NAME,fb.getUser().getName());
				}
				
				commHandler.writeToRmoteDevice(sendData);
			}
			else if(recevieToWhere == DATA_FACEBOOK_USER_ID){
				MyFacebook fb = app.getFacebook();
				// receive data
				// if data received not equals to DATA_FACEBOOK_NO_ID so other device connected with facebook
				// if not other device not connected with facebook
				if(!strReceivesData[1].equals(DATA_FACEBOOK_NO_ID)){
					fb.setCompetitorUserID(strReceivesData[1]);
				}
				// send data
				sendData = buildData(DATA_FACEBOOK_USER_ID,DATA_FACEBOOK_NO_ID);
				if(fb.isOpenedConnection()){
					sendData = buildData(DATA_FACEBOOK_USER_ID,fb.getUser().getId());
				}
				commHandler.writeToRmoteDevice(sendData);
			}
			else if(recevieToWhere == DATA_DEVICE_NAME){
				// receive data
				app.setCompetitorDeviceName(strReceivesData[1]);
				// send data
				sendData = buildData(DATA_DEVICE_NAME,app.getMyDeviceName());
				commHandler.writeToRmoteDevice(sendData);
			}
			else if(recevieToWhere == DATA_FINISH){
				sendData = buildData(DATA_FINISH,DATA_FINISH);
				commHandler.writeToRmoteDevice(sendData);
				Sync.waitTime(timeAir);
				iSyncStateChanged.finishedSync();
			}
		}
	}
	public void resetSync(){
		server.counterReceiveData = 0;
		avgAirTime = 0;
		avgTotalRoundTrip = 0;
	}
	private void writeResultSync()
	{
		String filename = "SyncResults.txt";
		File file = new File(Environment.getExternalStorageDirectory(), filename);
		try {
		    PrintWriter pw = new PrintWriter(new FileOutputStream(file));
		    for(int i=0;i<MAX_PACKEAGES;i++)
		    {
		    	pw.println("number round is:" + i);
		    	pw.println(arrAirTime[i]);
		    	pw.println(arrTotalTime[i]);
		    	pw.println("********************************************************");
		    }
		    pw.println("********************************************************");
		    pw.println("the air time average is:" + avgAirTime/MAX_PACKEAGES);
		    pw.println("the toatl ronud trip average is:" + avgTotalRoundTrip/MAX_PACKEAGES);
		    pw.println("********************************************************");
		    pw.flush();
		    pw.close();
		} catch (FileNotFoundException e) {
		    try {
				file.createNewFile();
				writeResultSync();
				Log.d(MyLog.SYNC_EXEPTION,"FileNotFoundException this exception throw beacuse created FileOutputStream message: " + e.getMessage());
			} catch (IOException e1) {
				Log.d(MyLog.SYNC_EXEPTION,"IOException this exception throw beacuse file.createNewFile() message: " + e.getMessage());
			}
		}
	}
	public interface ISyncStateChanged{
		void startedSync();
		void finishedSync();
	}
}


